home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmbase-grok-1.2 / chartdrw.c < prev    next >
C/C++ Source or Header  |  1995-06-25  |  11KB  |  417 lines

  1. /*
  2.  * draw a chart in the card form
  3.  *
  4.  *    draw_chart(card,nitem)
  5.  *    chart_action_callback(widget,event,args,nargs)
  6.  */
  7.  
  8. #include "config.h"
  9. #include <X11/Xos.h>
  10. #include <stdlib.h>
  11. #include <math.h>
  12. #include <stdlib.h>
  13. #include <Xm/Xm.h>
  14. #include "grok.h"
  15. #include "form.h"
  16. #include "proto.h"
  17.  
  18. static void drawrect(Window, ITEM *, int, int, int, int);
  19. static void drawbox (Window, ITEM *, int, int, int, int);
  20.  
  21. extern Display        *display;    /* everybody uses the same server */
  22. extern GC        gc;        /* everybody uses this context */
  23. extern XFontStruct    *font[NFONTS];    /* fonts: FONT_* */
  24. extern CARD         *curr_card;    /* card being displayed in main win */
  25.  
  26.  
  27. /*
  28.  * adjust x such that it is a multiple of s
  29.  */
  30.  
  31. static double snap(
  32.     double x,
  33.     double s)
  34. {
  35.     long i;
  36.     if (s < 1e-6) return(x);
  37.     i = x / s;
  38.     return(i * s);
  39. #if 0
  40.     long tmp = x * 1024;
  41.     if (s < 0) s = -s;
  42.     if (s < 1e-6) return(x);
  43.     tmp -= tmp % (int)(s * 1024);
  44.     return(tmp / 1024.0);
  45. #endif
  46. }
  47.  
  48.  
  49. /*
  50.  * redraw a single chart defined by an item into a drawing area widget.
  51.  */
  52.  
  53. #define XPIX(x)   ((int)(((x) - xmin) / (xmax - xmin) * item->xs))
  54. #define YPIX(y)   ((int)(((y) - ymin) / (ymax - ymin) * item->ys))
  55.  
  56. static float        xmin, xmax;    /* bounds of all bars in chart */
  57. static float        ymin, ymax;    /* bounds of all bars in chart */
  58.  
  59. void draw_chart(
  60.     CARD        *card,        /* life, the universe, and everything*/
  61.     int        nitem)        /* # of item in form */
  62. {
  63.     int        save_row;    /* save card->row (current card) */
  64.     Window        win;        /* window on screen to draw into */
  65.     register ITEM    *item;        /* chart item to draw */
  66.     register CHART    *chart;        /* describes current component */
  67.     char        *res;        /* result of expr evaluation */
  68.     register BAR    *bar;        /* current bar */
  69.     int        r, c;        /* row (card) and comp (bar) counters*/
  70.     int        i;        /* index values */
  71.     float        f;        /* coordinate in value space */
  72.  
  73.     if (!card || !card->form || !card->dbase || !card->dbase->nrows)
  74.         return;
  75.     item = card->form->items[nitem];
  76.     if (!item->ch_ncomp)
  77.         return;
  78.     win = XtWindow(card->items[nitem].w0);
  79.     save_row = card->row;
  80.  
  81.     /*
  82.      * step 1: calculate positions and colors of all bars
  83.      */
  84.     item->ch_nbars = item->ch_ncomp * card->dbase->nrows;
  85.     if (item->ch_bar)
  86.         free((void *)item->ch_bar);
  87.     if (!(item->ch_bar = (BAR *)malloc(item->ch_nbars * sizeof(BAR))))
  88.         fatal("no memory");
  89.  
  90.     xmin = ymin =  1e30;
  91.     xmax = ymax = -1e30;
  92.     bar = item->ch_bar;
  93.     for (r=0; r < card->dbase->nrows; r++) {
  94.         card->row = r;
  95.         for (c=0; c < item->ch_ncomp; c++, bar++) {
  96.             chart = &item->ch_comp[c];
  97.             if ((res=evaluate(card,chart->excl_if)) && atoi(res)) {
  98.                 mybzero((void *)bar, sizeof(BAR));
  99.                 continue;
  100.             }
  101.             if (res = evaluate(card, chart->color))
  102.                 bar->color = atoi(res) & 7;
  103.             for (i=0; i < 4; i++)
  104.                 switch(chart->value[i].mode) {
  105.                   default:
  106.                   case CC_NEXT:
  107.                     bar->value[i] =
  108.                         i ? c ? bar[-1].value[CC_Y] +
  109.                             bar[-1].value[CC_YS]
  110.                               : 0
  111.                           : xmax < xmin ? 0 : xmax;
  112.                     break;
  113.                   case CC_SAME:
  114.                     bar->value[i] =
  115.                         c ? bar[-1].value[i] : 0;
  116.                     break;
  117.                   case CC_EXPR:
  118.                     bar->value[i] =
  119.                         (res = evaluate(card,
  120.                             chart->value[i].expr))
  121.                           ? atof(res)
  122.                           : 0;
  123.                     break;
  124.                   case CC_DRAG:
  125.                     res = dbase_get(card->dbase, r,
  126.                             chart->value[i].field);
  127.                     bar->value[i] =
  128.                         res ? atof(res)
  129.                             * chart->value[i].mul
  130.                             + chart->value[i].add
  131.                             : 0;
  132.                 }
  133.             if (bar->value[2] < 0) {
  134.                 bar->value[0] += bar->value[2];
  135.                 bar->value[2] = -bar->value[2];
  136.             }
  137.             if (bar->value[3] < 0) {
  138.                 bar->value[1] += bar->value[3];
  139.                 bar->value[3] = -bar->value[3];
  140.             }
  141.             if (bar->value[0] < xmin)
  142.                 xmin = bar->value[0];
  143.             if (bar->value[1] < ymin)
  144.                 ymin = bar->value[1];
  145.             if (bar->value[0] + bar->value[2] > xmax)
  146.                 xmax = bar->value[0] + bar->value[2];
  147.             if (bar->value[1] + bar->value[3] > ymax)
  148.                 ymax = bar->value[1] + bar->value[3];
  149.         }
  150.     }
  151.     if (!item->ch_xauto) {
  152.         xmin = item->ch_xmin;
  153.         xmax = item->ch_xmax;
  154.     } else {
  155.         if (xmin < 0)
  156.             xmin -= (xmax - xmin) * .05;
  157.         if (xmax > 0)
  158.             xmax += (xmax - xmin) * .05;
  159.     }
  160.     if (!item->ch_yauto) {
  161.         ymin = item->ch_ymin;
  162.         ymax = item->ch_ymax;
  163.     } else {
  164.         if (ymin < 0)
  165.             ymin -= (ymax - ymin) * .05;
  166.         if (ymax > 0)
  167.             ymax += (ymax - ymin) * .05;
  168.     }
  169.     if (xmin >= xmax || ymin >= ymax) {
  170.         card->row = save_row;
  171.         return;
  172.     }
  173.  
  174.     /*
  175.      * step 2: prepare background
  176.      */
  177.     set_color(COL_BACK);                /* draw background */
  178.     drawrect(win, item, 0, 0, item->xs, item->ys);
  179.  
  180.     set_color(COL_CHART_GRID);            /* draw grid lines */
  181.     if (item->ch_xgrid)
  182.         for (f=snap(xmin, item->ch_xgrid); f < xmax; f+=item->ch_xgrid)
  183.             drawrect(win, item, XPIX(f), 0, 1, item->ys);
  184.     if (item->ch_ygrid)
  185.         for (f=snap(ymin, item->ch_ygrid); f < ymax; f+=item->ch_ygrid)
  186.             drawrect(win, item, 0, YPIX(f), item->xs, 1);
  187.  
  188.     set_color(COL_CHART_AXIS);            /* draw axes */
  189.     drawrect(win, item, 0, YPIX(0), item->xs, 1);
  190.     drawrect(win, item, XPIX(0), 0, 1, item->ys);
  191.  
  192.     /*
  193.      * step 3: draw bars
  194.      */
  195.     bar = item->ch_bar;
  196.     for (r=0; r < card->dbase->nrows; r++) {
  197.         card->row = r;
  198.         for (c=0; c < item->ch_ncomp; c++, bar++) {
  199.             int x  = XPIX(snap(bar->value[0], item->ch_xsnap));
  200.             int xs = XPIX(snap(bar->value[0] +
  201.                        bar->value[2], item->ch_xsnap)) - x;
  202.             int y  = YPIX(snap(bar->value[1], item->ch_ysnap));
  203.             int ys = YPIX(snap(bar->value[1] +
  204.                        bar->value[3], item->ch_ysnap)) - y;
  205.             chart = &item->ch_comp[c];
  206.             if (!chart->xfat)
  207.                 x++, xs-=2;
  208.             if (!chart->yfat)
  209.                 y++, ys-=2;
  210.             set_color(COL_CHART_0 + bar->color);
  211.             drawrect(win, item, x, y, xs, ys);
  212.             if (r == save_row || !chart->xfat && !chart->yfat) {
  213.                 set_color(COL_STD);
  214.                 drawbox(win, item, x, y, xs, ys);
  215.             }
  216.             if (r == save_row) {
  217.                 set_color(COL_SHEET);
  218.                 drawbox(win, item, x+1, y+1, xs-2, ys-2);
  219.             }
  220.         }
  221.     }
  222.     card->row = save_row;
  223. }
  224.  
  225.  
  226. /*
  227.  * draw lines and boxes. All coordinates are doubles in the range 0..1,
  228.  * and assume 0/0 in the lower left corner, not in the upper right as X
  229.  * normally does.
  230.  */
  231.  
  232. #define CLIP \
  233.     if (x + xs > item->xs)    xs = item->xs - x;    \
  234.     if (x      < 0)        xs += x, x = 0;        \
  235.     if (y + ys > item->ys)    ys = item->ys - y;    \
  236.     if (y      < 0)        ys += y, y = 0;        \
  237.     if (xs <= 0 || ys <= 0)    return
  238.  
  239. static void drawrect(
  240.     Window        win,
  241.     ITEM        *item,
  242.     int        x,
  243.     int        y,
  244.     int        xs,
  245.     int        ys)
  246. {
  247.     CLIP;
  248.     XFillRectangle(display, win, gc, x, item->ys-ys-y, xs, ys);
  249. }
  250.  
  251. static void drawbox(
  252.     Window        win,
  253.     ITEM        *item,
  254.     int        x,
  255.     int        y,
  256.     int        xs,
  257.     int        ys)
  258. {
  259.     CLIP;
  260.     XDrawRectangle(display, win, gc, x, item->ys-ys-y, xs-1, ys-1);
  261. }
  262.  
  263.  
  264. /*
  265.  * given a x/y pixel coordinate in the drawing area, return the row number
  266.  * of the card that produced the bar, or -1 if no bar was hit
  267.  */
  268.  
  269. static int pick_chart(
  270.     CARD        *card,        /* life, the universe, and everything*/
  271.     int        nitem,        /* # of item in form */
  272.     int        *comp,        /* returned component # */
  273.     int        xpick,        /* mouxe x/y pixel coordinate */
  274.     int        ypick)
  275. {
  276.     register ITEM    *item;        /* chart item to draw */
  277.     register CHART    *chart;        /* describes current component */
  278.     register BAR    *bar;        /* current bar */
  279.     int        r, c;        /* row (card) and comp (bar) counters*/
  280.  
  281.     if (!card || !card->form || !card->dbase || !card->dbase->nrows)
  282.         return(-1);
  283.     item = card->form->items[nitem];
  284.     if (!item->ch_ncomp)
  285.         return(-1);
  286.  
  287.     ypick = item->ys - ypick;
  288.     bar = item->ch_bar + card->dbase->nrows * item->ch_ncomp -1;
  289.     for (r=card->dbase->nrows-1; r >= 0; r--) {
  290.         for (c=item->ch_ncomp-1; c >= 0; c--, bar--) {
  291.             int x  = XPIX(snap(bar->value[0], item->ch_xsnap));
  292.             int xs = XPIX(snap(bar->value[0] +
  293.                        bar->value[2], item->ch_xsnap)) - x;
  294.             int y  = YPIX(snap(bar->value[1], item->ch_ysnap));
  295.             int ys = YPIX(snap(bar->value[1] +
  296.                        bar->value[3], item->ch_ysnap)) - y;
  297.             chart = &item->ch_comp[c];
  298.             if (!chart->xfat)
  299.                 x++, xs-=2;
  300.             if (!chart->yfat)
  301.                 y++, ys-=2;
  302.             if (xpick >= x && xpick < x + xs &&
  303.                 ypick >= y && ypick < y + ys) {
  304.                 *comp = c;
  305.                     return(r);
  306.             }
  307.         }
  308.     }
  309.     return(-1);
  310. }
  311.  
  312.  
  313. /*
  314.  * some button action (up, down, motion) has occured in a chart drawing area.
  315.  * The value written back is the field value -> pixel coordinate equation:
  316.  *    pix = ((fieldval * mul + add) - xmin) / (xmax - xmin) * item->xs
  317.  * solved for fieldval:
  318.  *    fieldval = (pix * (xmax - xmin) / item->xs + xmin - add) / mul
  319.  */
  320.  
  321. void chart_action_callback(
  322.     Widget        widget,        /* drawing area */
  323.     XButtonEvent    *event,        /* X event, contains position */
  324.     String        *args,        /* what happened, up/down/motion */
  325.     int        nargs)        /* # of args, must be 1 */
  326. {
  327.     static int    nitem;        /* item on which pen was pressed */
  328.     static int    row, col, comp;    /* row and column of dragged bar */
  329.     static int    down_x, down_y;    /* pos where pen was pressed down */
  330.     static double    x_val, y_val;    /* previous values of fields */
  331.     static BOOL    moving;        /* this is not a selection, move box */
  332.     ITEM        *item;        /* item being selected or moved */
  333.     CHART        *chart;        /* chart component being dragged */
  334.     struct value    *xval, *yval;    /* chart component value (x,y,xs,ys) */
  335.     int        x, y;        /* pixel coordinate of mouse */
  336.     double        f;        /* new db value */
  337.     char        buf[40];    /* new db value as numeric string */
  338.     char        *p;
  339.     BOOL        redraw = FALSE;
  340.     int        i;
  341.  
  342.     for (nitem=0; nitem < curr_card->nitems; nitem++)
  343.         if (widget == curr_card->items[nitem].w0 ||
  344.             widget == curr_card->items[nitem].w1)
  345.             break;
  346.     if (nitem >= curr_card->nitems    ||        /* illegal */
  347.         curr_card->dbase == 0    ||        /* preview dummy card*/
  348.         curr_card->row < 0)                /* card still empty */
  349.         return;
  350.     item = curr_card->form->items[nitem];
  351.  
  352.     if (!strcmp(args[0], "down")) {
  353.         moving = FALSE;
  354.         down_x = event->x;
  355.         down_y = event->y;
  356.         row    = pick_chart(curr_card, nitem, &comp, down_x, down_y);
  357.         if (row >= 0 && row < curr_card->dbase->nrows) {
  358.             card_readback_texts(curr_card, -1);
  359.             curr_card->row = row;
  360.             for (i=0; i < curr_card->nquery; i++)
  361.                 if (curr_card->query[i] == row) {
  362.                     curr_card->qcurr = i;
  363.                     break;
  364.                 }
  365.             fillout_card(curr_card, FALSE);
  366.             scroll_summary(curr_card);
  367.             chart = &item->ch_comp[comp];
  368.             p = dbase_get(curr_card->dbase, row,
  369.                         chart->value[CC_X].field);
  370.             x_val = p ? atof(p) : 0;
  371.             p = dbase_get(curr_card->dbase, row,
  372.                         chart->value[CC_Y].field);
  373.             y_val = p ? atof(p) : 0;
  374.         }
  375.         return;
  376.     }
  377.  
  378.     chart = &item->ch_comp[comp];
  379.     xval  = &chart->value[CC_X];
  380.     yval  = &chart->value[CC_Y];
  381.     if (xval->mode != CC_DRAG && yval->mode != CC_DRAG ||
  382.                         xmax <= xmin || ymax <= ymin)
  383.         return;
  384.  
  385.     if (!strcmp(args[0], "up")) {
  386.         if (moving) {
  387.             print_info_line();
  388.             fillout_card(curr_card, FALSE);
  389.         }
  390.         return;
  391.     }
  392.     x = abs(event->x - down_x);
  393.     y = abs(event->y - down_y);
  394.     moving |= x > 3 || y > 3;
  395.     if (!moving)
  396.         return;
  397.  
  398.     if (xval->mode == CC_DRAG && xval->mul != 0) {
  399.         x = event->x - down_x;
  400.         f = x_val + x * (xmax-xmin) / xval->mul / item->xs;
  401.         f = snap(f, item->ch_xsnap);
  402.         sprintf(buf, "%.12lg", f);
  403.         dbase_put(curr_card->dbase, row, xval->field, buf);
  404.         redraw = TRUE;
  405.     }
  406.     if (yval->mode == CC_DRAG && yval->mul != 0) {
  407.         y = event->y - down_y;
  408.         f = y_val + y * (ymax-ymin) / yval->mul / item->ys;
  409.         f = snap(f, item->ch_ysnap);
  410.         sprintf(buf, "%.12lg", f);
  411.         dbase_put(curr_card->dbase, row, yval->field, buf);
  412.         redraw = TRUE;
  413.     }
  414.     if (redraw)
  415.         draw_chart(curr_card, nitem);
  416. }
  417.